﻿using CPF;
using CPF.Animation;
using CPF.Charts;
using CPF.Controls;
using CPF.Drawing;
using CPF.Input;
using CPF.Shapes;
using CPF.Styling;
using CPF.Svg;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CPFUI.IControl
{
    [CPF.Design.DesignerLoadStyle("res://$safeprojectname$/Stylesheet1.css")]//用于设计的时候加载样式
    public class MindControl : Control
    {
        public MindNode MindNode;
        public MindControl()
        {
        }
        //模板定义
        protected override void InitializeComponent()
        {
            IsAntiAlias = true;
            
        }

#if !DesignMode //用户代码写到这里，设计器下不执行，防止设计器出错
        MindNode SelectedMindNode;
        protected override void OnInitialized()
        {
            base.OnInitialized();
        }
        bool isMoveNode = false;
        bool isConnectNode = false;
        Rect connectStartRect;
        Rect connectEndRect;
        MindNodeOrientation mindNodeStartOrientation;
        protected override void OnMouseDown(MouseButtonEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                CheckConnectNode(e.Location);
                connectLocation = e.Location;
                moveLocation = e.Location;
                CaptureMouse();
                Invalidate();
            }
            base.OnMouseDown(e);
        }
        public void CheckConnectNode(Point location )
        {
            //判断是否开始连接
            //判断鼠标是否在物体四个边的中心点，如果是，则开始连接节点
            if (IsPointInRectangle(location, MindNode.LeftRect()))
            {
                isConnectNode = true;
                connectEndRect = connectStartRect = MindNode.LeftRect();
                mindNodeStartOrientation = MindNodeOrientation.Left;
                SelectedMindNode = MindNode;
                return;
            }
            else if (IsPointInRectangle(location, MindNode.TopRect()))
            {
                isConnectNode = true;
                connectEndRect = connectStartRect = MindNode.TopRect();
                mindNodeStartOrientation = MindNodeOrientation.Top;
                SelectedMindNode = MindNode;
                return;
            }
            else if (IsPointInRectangle(location, MindNode.RightRect()))
            {
                isConnectNode = true;
                connectEndRect = connectStartRect = MindNode.RightRect();
                mindNodeStartOrientation = MindNodeOrientation.Right;
                SelectedMindNode = MindNode;
                return;
            }
            else if (IsPointInRectangle(location, MindNode.BottomRect()))
            {
                isConnectNode = true;
                connectEndRect = connectStartRect = MindNode.BottomRect();
                mindNodeStartOrientation = MindNodeOrientation.Bottom;
                SelectedMindNode = MindNode;
                return;
            }
            //判断是否移动
            //判断鼠标是否在物体内，如果是，则开始连接节点
            else if (IsPointInRectangle(location, new Rect(MindNode.Left, MindNode.Top, MindNode.Size.Width.Value, MindNode.Size.Height.Value)))
            {
                isMoveNode = true;
                SelectedMindNode = MindNode;
                itemLocation = new Point(SelectedMindNode.Left, SelectedMindNode.Top);
                return;
            }
            CheckConnectNode(location, MindNode.NextNode);
        }
        public bool CheckConnectNode(Point location,Collection<MindNode> nodes)
        {
            bool ispointInRect = false;
            for (int i = nodes.Count - 1; i >= 0; i--)
            {
                //判断是否开始连接
                //判断鼠标是否在物体四个边的中心点，如果是，则开始连接节点
                if (IsPointInRectangle(location, nodes[i].LeftRect()))
                {
                    isConnectNode = true;
                    SelectedMindNode = nodes[i];
                    connectEndRect = connectStartRect = nodes[i].LeftRect();
                    mindNodeStartOrientation = MindNodeOrientation.Left;
                    ispointInRect = true;
                    break;
                }
                else if (IsPointInRectangle(location, nodes[i].TopRect()))
                {
                    isConnectNode = true;
                    SelectedMindNode = nodes[i];
                    connectEndRect = connectStartRect = nodes[i].TopRect();
                    mindNodeStartOrientation = MindNodeOrientation.Top;
                    ispointInRect = true;
                    break;
                }
                else if (IsPointInRectangle(location, nodes[i].RightRect()))
                {
                    isConnectNode = true;
                    SelectedMindNode = nodes[i];
                    connectEndRect = connectStartRect = nodes[i].RightRect();
                    mindNodeStartOrientation = MindNodeOrientation.Right;
                    ispointInRect = true;
                    break;
                }
                else if (IsPointInRectangle(location, nodes[i].BottomRect()))
                {
                    isConnectNode = true;
                    SelectedMindNode = nodes[i]; 
                    connectEndRect = connectStartRect = nodes[i].BottomRect();
                    mindNodeStartOrientation = MindNodeOrientation.Bottom;
                    ispointInRect = true;
                    break;
                }
                //判断是否移动
                //判断鼠标是否在物体内，如果是，则开始连接节点
                else if (IsPointInRectangle(location, new Rect(nodes[i].Left, nodes[i].Top, nodes[i].Size.Width.Value, nodes[i].Size.Height.Value)))
                {
                    isMoveNode = true;
                    SelectedMindNode = nodes[i];
                    itemLocation = new Point(SelectedMindNode.Left, SelectedMindNode.Top);
                    ispointInRect = true;
                    break;
                }
                CheckConnectNode(location, nodes[i].NextNode) ;
            }
            return ispointInRect;
        }
        protected override void OnMouseUp(MouseButtonEventArgs e)
        {
            
            base.OnMouseUp(e);
            if (e.LeftButton == MouseButtonState.Released)
            {
                if (isConnectNode)
                {
                    Point nodeLocation = new Point();
                    switch (mindNodeStartOrientation)
                    {
                        case MindNodeOrientation.Left:
                            nodeLocation = new Point(connectEndRect.X - 100+3, connectEndRect.Y - 25 + 3);
                            break;
                        case MindNodeOrientation.Right:
                            nodeLocation = new Point(connectEndRect.X+3 , connectEndRect.Y - 25+3);
                            break;
                        case MindNodeOrientation.Top:
                            nodeLocation = new Point(connectEndRect.X - 50+3, connectEndRect.Y - 50+3);
                            break;
                        case MindNodeOrientation.Bottom:
                            nodeLocation = new Point(connectEndRect.X - 50+3, connectEndRect.Y+3);
                            break;
                    }
                    SelectedMindNode.NextNode.Add(new MindNode { Left = nodeLocation.X, Top = nodeLocation.Y,Caption="节点", Size = new SizeField(100, 50), GraphType = MindNodeGraphType.Rectangle, Orientation = mindNodeStartOrientation });
                }
                ReleaseMouseCapture();
                Invalidate();
            }
            isMoveNode = false;
            isConnectNode = false;
        }
        private Point moveLocation;
        private Point itemLocation;
        private Point connectLocation;
        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                if (isMoveNode)
                {
                    if (SelectedMindNode == null)
                    {
                        return;
                    }
                    var a = e.Location - moveLocation;
                    SelectedMindNode.Left = itemLocation.X + a.X;//=new Point(SelectedMindNode.Location.X + a.X, SelectedMindNode.Location.Y + a.Y);
                    SelectedMindNode.Top = itemLocation.Y + a.Y;
                }
                else if (isConnectNode)
                {
                    connectLocation = e.Location;
                    connectEndRect = new Rect(e.Location.X - 3, e.Location.Y - 3, 6, 6);
                }
                Invalidate();
                // TransformPoint
            }
            base.OnMouseMove(e);
        }
        Font Font = new Font("微软雅黑", 11, FontStyles.Regular);
        //用户代码
        protected override void OnRender(DrawingContext dc)
        {
            base.OnRender(dc);
            Point pstart = new Point();
            using (Brush lineBrush = new SolidColorBrush(Color.DarkGreen))
            {

                using (Brush boradbrush = new SolidColorBrush(Color.DodgerBlue))
                {
                    using (Brush back = new SolidColorBrush(Color.White))
                    {
                        MindNode item = MindNode;
                        PathGeometry pathRect = new PathGeometry();
                       
                        //dc.DrawString(new Point(item.Left, item.Top), b, string.Format("{0}:{1}",item.Left,item.Top),new Font("微软雅黑",9));
                        Point pend = new Point(item.Left, item.Size.Height.Value / 2 + item.Top);
                        DrawLine(dc, MindNode.NextNode, item); 
                        switch (item.GraphType)
                        {
                            case MindNodeGraphType.Circle:
                                dc.FillEllipse(back, new Point(item.Left + item.Size.Width.Value / 2, item.Top + item.Size.Height.Value / 2), item.Size.Width.Value / 2, item.Size.Height.Value / 2);
                                dc.DrawEllipse(boradbrush, new Stroke(2), new Point(item.Left + item.Size.Width.Value / 2, item.Top + item.Size.Height.Value / 2), item.Size.Width.Value / 2, item.Size.Height.Value / 2);
                                if (SelectedMindNode == item)
                                {
                                    dc.DrawEllipse(lineBrush, new Stroke(2), new Point(item.Left + item.Size.Width.Value / 2, item.Top + item.Size.Height.Value / 2), item.Size.Width.Value / 2, item.Size.Height.Value / 2);
                                }
                                break;
                            case MindNodeGraphType.Rectangle:
                                dc.FillRectangle(back, new Rect(item.Left, item.Top, item.Size.Width.Value, item.Size.Height.Value));
                                dc.DrawRectangle(boradbrush, new Stroke(2), new Rect(item.Left, item.Top, item.Size.Width.Value, item.Size.Height.Value));
                                if (SelectedMindNode == item)
                                {
                                    dc.DrawRectangle(lineBrush, new Stroke(2), new Rect(item.Left, item.Top, item.Size.Width.Value, item.Size.Height.Value));
                                }
                                break;
                            case MindNodeGraphType.Triangle:
                                pathRect = new PathGeometry();
                                pathRect.BeginFigure(item.Left + item.Size.Width.Value / 2, item.Top);
                                pathRect.LineTo(item.Left + item.Size.Width.Value, item.Top + item.Size.Height.Value);
                                pathRect.LineTo(item.Left, item.Top + item.Size.Height.Value);
                                pathRect.EndFigure(true);
                                dc.FillPath(back, pathRect);
                                dc.DrawPath(boradbrush, new Stroke(2), pathRect);
                                if (SelectedMindNode == item)
                                {
                                    dc.DrawPath(lineBrush, new Stroke(2), pathRect);
                                }
                                break;
                            case MindNodeGraphType.Rhombus:
                                pathRect = new PathGeometry();
                                pathRect.BeginFigure(item.Left + item.Size.Width.Value / 2, item.Top);
                                pathRect.LineTo(item.Left + item.Size.Width.Value, item.Top + item.Size.Height.Value / 2);
                                pathRect.LineTo(item.Left + item.Size.Width.Value / 2, item.Top + item.Size.Height.Value);
                                pathRect.LineTo(item.Left, item.Top + item.Size.Height.Value / 2);
                                pathRect.EndFigure(true);
                                dc.FillPath(back, pathRect);
                                dc.DrawPath(boradbrush, new Stroke(2), pathRect);
                                if (SelectedMindNode == item)
                                {
                                    dc.DrawPath(lineBrush, new Stroke(2), pathRect);
                                }
                                break;
                        }

                        dc.DrawString(new Point(item.Left, item.Top + item.Size.Height.Value / 2 - Font.DefaultLineHeight / 2), boradbrush, item.Caption, Font, TextAlignment.Center, item.Size.Width.Value);
                        DrawControl(dc, MindNode.NextNode, item); 
                        if (isConnectNode)
                        {
                            Point sp = new Point(connectStartRect.X + 3, connectStartRect.Y + 3);
                            Point ep = new Point(connectEndRect.X + 3, connectEndRect.Y + 3);
                            PathGeometry bezierpath = GetBezierPath(sp, ep, mindNodeStartOrientation);
                            dc.FillEllipse(lineBrush, sp, 3, 3);
                            dc.FillEllipse(lineBrush, ep, 3, 3);
                            dc.DrawPath(lineBrush, new Stroke(2), bezierpath);
                        }
                        if (SelectedMindNode !=null)
                        {
                            dc.DrawRectangle(lineBrush, new Stroke(2), SelectedMindNode.LeftRect());
                            dc.DrawRectangle(lineBrush, new Stroke(2), SelectedMindNode.TopRect());
                            dc.DrawRectangle(lineBrush, new Stroke(2), SelectedMindNode.RightRect());
                            dc.DrawRectangle(lineBrush, new Stroke(2), SelectedMindNode.BottomRect());
                            switch (SelectedMindNode.GraphType)
                            {
                                case MindNodeGraphType.Circle:
                                    dc.FillEllipse(back, new Point(SelectedMindNode.Left + SelectedMindNode.Size.Width.Value / 2, SelectedMindNode.Top + SelectedMindNode.Size.Height.Value / 2), SelectedMindNode.Size.Width.Value / 2, SelectedMindNode.Size.Height.Value / 2);
                                    dc.DrawEllipse(boradbrush, new Stroke(2), new Point(SelectedMindNode.Left + SelectedMindNode.Size.Width.Value / 2, SelectedMindNode.Top + SelectedMindNode.Size.Height.Value / 2), SelectedMindNode.Size.Width.Value / 2, SelectedMindNode.Size.Height.Value / 2);
                                    if (SelectedMindNode == SelectedMindNode)
                                    {
                                        dc.DrawEllipse(lineBrush, new Stroke(2), new Point(SelectedMindNode.Left + SelectedMindNode.Size.Width.Value / 2, SelectedMindNode.Top + SelectedMindNode.Size.Height.Value / 2), SelectedMindNode.Size.Width.Value / 2, SelectedMindNode.Size.Height.Value / 2);
                                    }
                                    break;
                                case MindNodeGraphType.Rectangle:
                                    dc.FillRectangle(back, new Rect(SelectedMindNode.Left, SelectedMindNode.Top, SelectedMindNode.Size.Width.Value, SelectedMindNode.Size.Height.Value));
                                    dc.DrawRectangle(boradbrush, new Stroke(2), new Rect(SelectedMindNode.Left, SelectedMindNode.Top, SelectedMindNode.Size.Width.Value, SelectedMindNode.Size.Height.Value));
                                    if (SelectedMindNode == SelectedMindNode)
                                    {
                                        dc.DrawRectangle(lineBrush, new Stroke(2), new Rect(SelectedMindNode.Left, SelectedMindNode.Top, SelectedMindNode.Size.Width.Value, SelectedMindNode.Size.Height.Value));
                                    }
                                    break;
                                case MindNodeGraphType.Triangle:
                                    pathRect = new PathGeometry();
                                    pathRect.BeginFigure(SelectedMindNode.Left + SelectedMindNode.Size.Width.Value / 2, SelectedMindNode.Top);
                                    pathRect.LineTo(SelectedMindNode.Left + SelectedMindNode.Size.Width.Value, SelectedMindNode.Top + SelectedMindNode.Size.Height.Value);
                                    pathRect.LineTo(SelectedMindNode.Left, SelectedMindNode.Top + SelectedMindNode.Size.Height.Value);
                                    pathRect.EndFigure(true);
                                    dc.FillPath(back, pathRect);
                                    dc.DrawPath(boradbrush, new Stroke(2), pathRect);
                                    if (SelectedMindNode == SelectedMindNode)
                                    {
                                        dc.DrawPath(lineBrush, new Stroke(2), pathRect);
                                    }
                                    break;
                                case MindNodeGraphType.Rhombus:
                                    pathRect = new PathGeometry();
                                    pathRect.BeginFigure(SelectedMindNode.Left + SelectedMindNode.Size.Width.Value / 2, SelectedMindNode.Top);
                                    pathRect.LineTo(SelectedMindNode.Left + SelectedMindNode.Size.Width.Value, SelectedMindNode.Top + SelectedMindNode.Size.Height.Value / 2);
                                    pathRect.LineTo(SelectedMindNode.Left + SelectedMindNode.Size.Width.Value / 2, SelectedMindNode.Top + SelectedMindNode.Size.Height.Value);
                                    pathRect.LineTo(SelectedMindNode.Left, SelectedMindNode.Top + SelectedMindNode.Size.Height.Value / 2);
                                    pathRect.EndFigure(true);
                                    dc.FillPath(back, pathRect);
                                    dc.DrawPath(boradbrush, new Stroke(2), pathRect);
                                    if (SelectedMindNode == SelectedMindNode)
                                    {
                                        dc.DrawPath(lineBrush, new Stroke(2), pathRect);
                                    }
                                    break;
                            }

                            dc.DrawString(new Point(SelectedMindNode.Left, SelectedMindNode.Top + SelectedMindNode.Size.Height.Value / 2 - Font.DefaultLineHeight / 2), boradbrush, SelectedMindNode.Caption, Font, TextAlignment.Center, SelectedMindNode.Size.Width.Value);

                        }
                    }
                    
                }
            }
        }
        public void DrawLine(DrawingContext dc, Collection<MindNode> nodes, MindNode previousitem)
        {
            using (Brush lineBrush = new SolidColorBrush(Color.DarkGreen))
            {
                using (Brush boradbrush = new SolidColorBrush(Color.DodgerBlue))
                {
                    using (Brush back = new SolidColorBrush(Color.White))
                    {
                        for (int i = 0; i < nodes.Count; i++)
                        {
                            MindNode item = nodes[i];
                            PathGeometry pathRect = new PathGeometry();
                            Point pstart = previousitem.GetStartConnectPointForNextNode(item.Orientation);
                            Point pend = item.GetStartConnectPoint();
                            PathGeometry bezierpath = GetBezierPath(pstart, pend, item.Orientation);
                            dc.FillEllipse(lineBrush, pstart, 3, 3);
                            dc.FillEllipse(lineBrush, pend, 3, 3);
                            dc.DrawPath(lineBrush, new Stroke(2), bezierpath);
                            //previousitem = item;
                            DrawLine(dc, nodes[i].NextNode, item);
                        }
                    }
                }
            }
        }
        public void DrawControl(DrawingContext dc, Collection<MindNode> nodes, MindNode previousitem)
        {
            using (Brush lineBrush = new SolidColorBrush(Color.DarkGreen))
            {
                using (Brush boradbrush = new SolidColorBrush(Color.DodgerBlue))
                {
                    using (Brush back = new SolidColorBrush(Color.White))
                    {
                        for (int i = 0; i < nodes.Count; i++)
                        {
                            MindNode item = nodes[i];
                            PathGeometry pathRect = new PathGeometry();
                            switch (item.GraphType)
                            {
                                case MindNodeGraphType.Circle:
                                    dc.FillEllipse(back, new Point(item.Left + item.Size.Width.Value / 2, item.Top + item.Size.Height.Value / 2), item.Size.Width.Value / 2, item.Size.Height.Value / 2);
                                    dc.DrawEllipse(boradbrush, new Stroke(2), new Point(item.Left + item.Size.Width.Value / 2, item.Top + item.Size.Height.Value / 2), item.Size.Width.Value / 2, item.Size.Height.Value / 2);
                                    if (SelectedMindNode == item)
                                    {
                                        dc.DrawEllipse(lineBrush, new Stroke(2), new Point(item.Left + item.Size.Width.Value / 2, item.Top + item.Size.Height.Value / 2), item.Size.Width.Value / 2, item.Size.Height.Value / 2);
                                    }
                                    break;
                                case MindNodeGraphType.Rectangle:
                                    dc.FillRectangle(back, new Rect(item.Left, item.Top, item.Size.Width.Value, item.Size.Height.Value));
                                    dc.DrawRectangle(boradbrush, new Stroke(2), new Rect(item.Left, item.Top, item.Size.Width.Value, item.Size.Height.Value));
                                    if (SelectedMindNode == item)
                                    {
                                        dc.DrawRectangle(lineBrush, new Stroke(2), new Rect(item.Left, item.Top, item.Size.Width.Value, item.Size.Height.Value));
                                    }
                                    break;
                                case MindNodeGraphType.Triangle:
                                    pathRect = new PathGeometry();
                                    pathRect.BeginFigure(item.Left + item.Size.Width.Value / 2, item.Top);
                                    pathRect.LineTo(item.Left + item.Size.Width.Value, item.Top + item.Size.Height.Value);
                                    pathRect.LineTo(item.Left, item.Top + item.Size.Height.Value);
                                    pathRect.EndFigure(true);
                                    dc.FillPath(back, pathRect);
                                    dc.DrawPath(boradbrush, new Stroke(2), pathRect);
                                    if (SelectedMindNode == item)
                                    {
                                        dc.DrawPath(lineBrush, new Stroke(2), pathRect);
                                    }
                                    break;
                                case MindNodeGraphType.Rhombus:
                                    pathRect = new PathGeometry();
                                    pathRect.BeginFigure(item.Left + item.Size.Width.Value / 2, item.Top);
                                    pathRect.LineTo(item.Left + item.Size.Width.Value, item.Top + item.Size.Height.Value / 2);
                                    pathRect.LineTo(item.Left + item.Size.Width.Value / 2, item.Top + item.Size.Height.Value);
                                    pathRect.LineTo(item.Left, item.Top + item.Size.Height.Value / 2);
                                    pathRect.EndFigure(true);
                                    dc.FillPath(back, pathRect);
                                    dc.DrawPath(boradbrush, new Stroke(2), pathRect);
                                    if (SelectedMindNode == item)
                                    {
                                        dc.DrawPath(lineBrush, new Stroke(2), pathRect);
                                    }
                                    break;
                            }

                            dc.DrawString(new Point(item.Left, item.Top + item.Size.Height.Value / 2 - Font.DefaultLineHeight / 2), boradbrush, item.Caption, Font, TextAlignment.Center, item.Size.Width.Value);

                            //previousitem = item;
                            DrawControl(dc, nodes[i].NextNode, item);
                        }
                    }
                }
            }
        }

        public PathGeometry GetBezierPath(Point startPoint,
            Point endPoint, MindNodeOrientation orientation)
        {
           List<Point> points = new List<Point>();
            points.Add(new Point(0,0));
            points.Add(new Point(0,0));
            var p = new PathGeometry();
            double valueX = Math.Pow(startPoint.X - endPoint.X, 2);
            double valueY = Math.Pow(startPoint.Y - endPoint.Y, 2);
            float value = (float)Math.Sqrt(valueX+ valueY)/3;
            switch (orientation)
            {
                case MindNodeOrientation.Left:
                    points[0] = new Point(startPoint.X - value, startPoint.Y);
                    points[1] = new Point(endPoint.X + value, endPoint.Y);
                    break;
                case MindNodeOrientation.Right:

                    points[0] = new Point(startPoint.X + value, startPoint.Y);
                    points[1] = new Point(endPoint.X - value, endPoint.Y);
                    break;
                case MindNodeOrientation.Top:
                    points[0] = new Point(startPoint.X, startPoint.Y - value);
                    points[1] = new Point(endPoint.X, endPoint.Y + value);
                    break;
                case MindNodeOrientation.Bottom:
                    points[0] = new Point(startPoint.X, startPoint.Y + value);
                    points[1] = new Point(endPoint.X, endPoint.Y - value);
                    break;
            }
            p.BeginFigure(startPoint.X, startPoint.Y);
            p.CubicTo(points[0], points[1],endPoint );
            return p;
        }
        public float Distance(Point p1, Point p2)
        {
            //C# code
            float width = p2.X - p1.X;
            float height = p2.Y - p1.Y;
            float result = (width * width) + (height * height);
            return (float)Math.Sqrt(result);//根号
        }
        public bool IsPointInRectangle(Point p, Rect rect)
        {
            return (p.X>= rect.Left && p.X <= rect.Right && p.Y >= rect.Top && p.Y <= rect.Bottom);
        }
#endif
    }
}
